#pragma once

#include <iostream>
#include <memory>
#include "Epoll.hpp"
#include "Socket.hpp"

const uint16_t defaultport=8080;

uint32_t EPOLL_IN(EPOLLIN);
uint32_t EPOLL_OUT(EPOLLOUT);

class Epollserver
{
public:
    static const int num=64;
public:
    Epollserver()
    :listen_ptr(new Sock())
    ,epoll_ptr(new Epoll())
    {
        listen_ptr->Socket();
        listen_ptr->Bind(defaultport);
        listen_ptr->Listen();
    }

    void Accpter()
    {
        string ip;
        uint16_t port;

        int fd=listen_ptr->Accpect(&ip,&port);
        if(fd<0)
        {
            lg("Warning","accpect error");
            return ;
        }

        lg("Info","acquire a now link ip=%s,port=%d,fd=%d",ip.c_str(),port,fd);
        epoll_ptr->Epoll_Updata(EPOLL_CTL_ADD,fd,EPOLL_IN);
    }

    void Recv(int sock,int pos)
    {
        std::cout << "recv" << std::endl;
        char buffer[1024];
        int n=read(sock,buffer,sizeof(buffer)-1);
        if(n>0)
        {
            buffer[n]=0;
            cout<<"get a message "<<buffer<<endl;

            // string ret="server echo# hello world";
            // write(sock,ret.c_str(),ret.size());
        }
        else if(n==0)
        {
            lg("Info","client close fd=%d",sock);
            epoll_ptr->Epoll_Updata(EPOLL_CTL_DEL,sock,EPOLL_OUT);
            close(sock);
        }
        else
        {
            lg("Info","rece error fd=%d",sock);
            epoll_ptr->Epoll_Updata(EPOLL_CTL_DEL,sock,EPOLLOUT);
            close(sock);
        }

    }

    void Dispatch(struct epoll_event*events,int n)
    {
        for(int i=0;i<n;i++)
        {
            int fd=events[i].data.fd;
            uint32_t event=events[i].events;
            if(event==EPOLL_IN)
            {
                if(fd==listen_ptr->Fd())
                {
                    Accpter();
                }
                else
                {
                    Recv(fd,i);
                }
            }
        }
    }

    void Start()
    {
        int listensock=listen_ptr->Fd();
        epoll_ptr->Epoll_Updata(EPOLL_CTL_ADD,listensock,EPOLL_IN);
        struct epoll_event events[num];
        for(;;)
        {
            int n=epoll_ptr->Epoll_Wait(events,num);
            if(n>0)
            {
                std::cout << "相应的fd个数是:" << n << std::endl;
                lg("Info","event happened fd =%d",events[0].data.fd);
                Dispatch(events,n);
            }
            else if(n==0)
            {
                lg("Info","time out ...");
            }
            else
            {
                lg("Error","epoll_wait error");
            }
        }
    }


private:
    unique_ptr<Sock> listen_ptr;
    unique_ptr<Epoll> epoll_ptr;
};